package com.lj.demo.springbootshirojwt.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.lj.demo.springbootshirojwt.dao.UserMapper;
import com.lj.demo.springbootshirojwt.entity.User;
import com.lj.demo.springbootshirojwt.service.IUserService;
import com.lj.demo.springbootshirojwt.util.Constants;
import com.lj.demo.springbootshirojwt.util.HttpRequestUtil;
import com.lj.demo.springbootshirojwt.util.JWTUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Title: 用户service实现类
 * Description:
 * Date: 2019年06月24日 14:29
 *
 * @author lvjie@hiynn.com
 * @version 1.0
 * Significant Modify：
 * Date                  Author                 Content
 * =================================================================
 * 2019年06月24日         lvjie@hiynn.com         创建文件,实现基本功能
 * =================================================================
 */
//@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private HttpServletRequest request;

    /**
     * 根据用户名获取用户信息
     * @param userName 用户名
     * @return
     */
    @Override
    public User getUserByUserName(String userName){
        User user = (User) redisTemplate.opsForValue().get(userName + Constants.REDIS_KEY_USER);
        if (Objects.equals(user,null)){
            user = userMapper.getUserByUserName(userName);
        }
        return user;
    }

    /**
     * 登录流程：
     * 1、根据用户名（userName）查询密码（password）进行比对登录 成功则进行下一步
     * 2、根据userName查询出用户信息（user）
     * 3、根据userName+roles+permissions+expireTime生成token和refreshToken（作用请参考realm的认证流程）
     * 4、将user+token+refreshToken返回前端
     * @param userName 用户名
     * @param password 密码
     * @return token+user
     */
    @Override
    public Map<String, Object> login(String userName, String password) {
        String passwordByUserName = userMapper.getPasswordByUserName(userName);
        if (!Objects.equals(password,passwordByUserName)){
            throw new AuthorizationException("用户名或密码错误");
        }
        //获取请求IP地址
        String ip = HttpRequestUtil.getIpAdrress(request);
        //移除登录黑名单
        Constants.blackList.remove(userName+"_"+ip);
        //获取用户信息
        User user = userMapper.getUserByUserName(userName);
        //所有角色
        List<String> roles = user.getRoles().stream().map(role -> role.getName()).collect(Collectors.toList());
        //所有权限
        List<String> permissions = Lists.newArrayList();
        user.getRoles().stream().map(role ->
             role.getAuthorizes().stream().map(authorize -> authorize.getName()).collect(Collectors.toList())
        ).forEach(list->
                list.stream().forEach(permission->
                        permissions.add(permission)
                )
        );
        //生成token  并设置失效时间
        String token = JWTUtil.sign(userName,passwordByUserName,Constants.TOKEN_EXPIRE_TIME,roles,permissions);
        //生成刷新token  并设置失效时间
        String refreshToken = JWTUtil.sign(userName,passwordByUserName,Constants.REFRESH_TOKEN_EXPIRE_TIME);
        //存储用户密码，用于验证token合法性
        Constants.passwordContainer.put(userName,passwordByUserName);
        Map<String,Object> resultMap = Maps.newHashMapWithExpectedSize(2);
        resultMap.put("user",user);
        resultMap.put(Constants.TOKEN_KEY,token);
        resultMap.put(Constants.REFRESH_TOKEN_KEY,refreshToken);
        return resultMap;
    }

    /**
     * 登出  登录可访问
     */
    @Override
    public void logout() {
        String ip = HttpRequestUtil.getIpAdrress(request);
        String token = HttpRequestUtil.getTokenFromRequest(request);
        String userName = JWTUtil.getUserName(token);
        String password = Constants.passwordContainer.get(userName);
        if (JWTUtil.verify(token,password)){
            throw new AuthorizationException("token不合法");
        }

        //移除登录信息信息
        Constants.tokenContainer.remove(userName+"_"+ip);
        //添加登录黑名单
        Constants.blackList.add(userName+"_"+ip);
        //清除shiro信息
        SecurityUtils.getSubject().logout();

    }
}
